home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / MFC_Samples / mtgdi / threads.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  10.3 KB  |  339 lines

  1. // threads.cpp : contains all the different GDI thread classes
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1999 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14. #include "mtgdi.h"
  15. #include "threads.h"
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char BASED_CODE THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. // critical section to protect while drawing to the DC
  23. CRITICAL_SECTION CGDIThread::m_csGDILock;
  24. CCriticalSection CGDIThread::m_oCriticalSection;
  25.  
  26. // m_hAnotherDead is used to signal that one or more threads have ended
  27. //    (it is an auto-reset event; and starts out not signaled)
  28. HANDLE CGDIThread::m_hAnotherDead = CreateEvent(NULL, FALSE, FALSE, NULL);
  29.  
  30. /////////////////////////////////////////////////////////////////////////////
  31. // CGDIThread
  32.  
  33. IMPLEMENT_DYNAMIC(CGDIThread, CWinThread)
  34.  
  35. BEGIN_MESSAGE_MAP(CGDIThread, CWinThread)
  36.     //{{AFX_MSG_MAP(CGDIThread)
  37.         // NOTE - the ClassWizard will add and remove mapping macros here.
  38.     //}}AFX_MSG_MAP
  39. END_MESSAGE_MAP()
  40.  
  41. CGDIThread::CGDIThread(CWnd* pWnd, HDC hDC)
  42. {
  43.     m_bAutoDelete = FALSE;
  44.     m_pMainWnd = pWnd;
  45.     m_pMainWnd->GetClientRect(&m_rectBorder);
  46.     m_hDC = hDC;
  47.  
  48.     // kill event starts out in the signaled state
  49.     m_hEventKill = CreateEvent(NULL, TRUE, FALSE, NULL);
  50.     m_hEventDead = CreateEvent(NULL, TRUE, FALSE, NULL);
  51. }
  52.  
  53. // The reason we don't just get a CDC from our owner and simply use it is because 
  54. // MFC GDI objects can't be passed between threads.  So we must instead pass a 
  55. // handle and then reconvert them back to MFC objects.  The reason  for this is 
  56. // because MFC maintains a list of all GDI objects on a per thread basis.  So if 
  57. // you pass a GDI object to another thread, it won't be in the correct list 
  58. // and MFC will assert.
  59.  
  60. BOOL CGDIThread::InitInstance()
  61. {
  62.     // thread setup
  63.     m_dc.Attach(m_hDC);
  64.  
  65.     // loop but check for kill notification
  66.     while (WaitForSingleObject(m_hEventKill, 0) == WAIT_TIMEOUT)
  67.         SingleStep();
  68.  
  69.     // thread cleanup
  70.     m_dc.Detach();
  71.  
  72.     // avoid entering standard message loop by returning FALSE
  73.     return FALSE;
  74. }
  75.  
  76. void CGDIThread::Delete()
  77. {
  78.     // calling the base here won't do anything but it is a good habit
  79.     CWinThread::Delete();
  80.  
  81.     // acknowledge receipt of kill notification
  82. #ifdef _WIN32_WCE_EMULATION
  83.     VERIFY(SetEvent(m_hEventDead));
  84.     VERIFY(SetEvent(m_hAnotherDead));
  85. #else
  86.     VERIFY(EventModify(m_hEventDead, EVENT_SET));
  87.     VERIFY(EventModify(m_hAnotherDead, EVENT_SET));
  88. #endif
  89. }
  90.  
  91. CGDIThread::~CGDIThread()
  92. {
  93.     CloseHandle(m_hEventKill);
  94.     CloseHandle(m_hEventDead);
  95. }
  96.  
  97. void CGDIThread::KillThread()
  98. {
  99.     // Note: this function is called in the context of other threads,
  100.     //    not the thread itself.
  101.  
  102.     // reset the m_hEventKill which signals the thread to shutdown
  103. #ifdef _WIN32_WCE_EMULATION
  104.     VERIFY(SetEvent(m_hEventKill));
  105. #else
  106.     VERIFY(EventModify(m_hEventKill, EVENT_SET));
  107. #endif
  108.  
  109.     // allow thread to run at higher priority during kill process
  110.     SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
  111.     WaitForSingleObject(m_hEventDead, INFINITE);
  112.     WaitForSingleObject(m_hThread, INFINITE);
  113.  
  114.     // now delete CWinThread object since no longer necessary
  115.     delete this;
  116. }
  117.  
  118. void CGDIThread::UpdateBorder()
  119. {
  120.     // Since another thread can access this variable, we block them when we write 
  121.     // it. In this case, it is overkill since the other thread would just animate 
  122.     // in the wrong direction while reading intermediate values and finally adjust 
  123.     // itself when the new value is valid.  It is a good idea to avoid such
  124.     // anomalies, however.
  125.  
  126.     EnterCriticalSection(&CGDIThread::m_csGDILock);
  127.     {
  128.         m_pMainWnd->GetClientRect(&m_rectBorder);
  129.     }
  130.     LeaveCriticalSection(&CGDIThread::m_csGDILock);
  131. }
  132.  
  133. /////////////////////////////////////////////////////////////////////////////
  134. // CBallThread
  135.  
  136. IMPLEMENT_DYNAMIC(CBallThread, CGDIThread)
  137.  
  138. BEGIN_MESSAGE_MAP(CBallThread, CGDIThread)
  139.     //{{AFX_MSG_MAP(CBallThread)
  140.         // NOTE - the ClassWizard will add and remove mapping macros here.
  141.     //}}AFX_MSG_MAP
  142. END_MESSAGE_MAP()
  143.  
  144. CBallThread::CBallThread(CWnd* pWnd, HDC hDC, CPoint ptPos, CPoint ptVel, 
  145.     CSize Size, COLORREF color)
  146.     : CGDIThread(pWnd,hDC)
  147. {
  148.     m_rectPosition.SetRect(ptPos.x,ptPos.y,ptPos.x+Size.cx,ptPos.y+Size.cx);
  149.     m_ptVelocity = ptVel;
  150.  
  151.     CBrush brush(color);
  152.     m_hBrush = (HBRUSH)brush.Detach();
  153. }
  154.  
  155. // The reason we don't just store the CBrush from our owner and simply use it is 
  156. // because MFC GDI objects can't be passed between threads.  So we must instead 
  157. // pass a handle and then reconvert them back to MFC objects.  The reason for 
  158. // this is because MFC maintains a list of all GDI objects on a per thread basis.  
  159. // So if you pass a GDI object to another thread, it won't be in the correct 
  160. // list and MFC will assert.
  161.  
  162. BOOL CBallThread::InitInstance()
  163. {
  164.     m_brush.Attach(m_hBrush);
  165.  
  166.     return CGDIThread::InitInstance();
  167. }
  168.  
  169.  
  170. void CBallThread::SingleStep()
  171. {
  172.     m_rectPosition.OffsetRect(m_ptVelocity);
  173.  
  174.     if (m_rectPosition.top<m_rectBorder.top) 
  175.         m_ptVelocity.y = (m_ptVelocity.y>0) ? m_ptVelocity.y : -m_ptVelocity.y;
  176.  
  177.     if (m_rectPosition.bottom>m_rectBorder.bottom) 
  178.         m_ptVelocity.y = (m_ptVelocity.y>0) ? -m_ptVelocity.y : m_ptVelocity.y;
  179.  
  180.     if (m_rectPosition.left<m_rectBorder.left) 
  181.         m_ptVelocity.x = (m_ptVelocity.x>0) ? m_ptVelocity.x : -m_ptVelocity.x;
  182.  
  183.     if (m_rectPosition.right>m_rectBorder.right) 
  184.         m_ptVelocity.x = (m_ptVelocity.x>0) ? -m_ptVelocity.x : m_ptVelocity.x;
  185.  
  186.     // Since all threads share the same HDC it is necessary
  187.     // to block all other threads while we render in the HDC
  188.  
  189.     // NOTE: We don't have to call csl.Unlock() since the csl lock is
  190.     //       destroyed when leave this function.
  191.     CSingleLock csl( &CGDIThread::m_oCriticalSection );
  192.     if (csl.Lock())
  193.     {
  194.         CBrush* oldbrush;
  195.         
  196.         oldbrush = m_dc.SelectObject(&m_brush);
  197.         m_dc.Ellipse(m_rectPosition);
  198.         m_dc.SelectObject(oldbrush);
  199.     }
  200.     csl.Unlock();
  201. }
  202.  
  203. /////////////////////////////////////////////////////////////////////////////
  204. //
  205. // CRectThread
  206. //
  207. /////////////////////////////////////////////////////////////////////////////
  208.  
  209. IMPLEMENT_DYNAMIC(CRectThread, CGDIThread)
  210.  
  211. BEGIN_MESSAGE_MAP(CRectThread, CCmdTarget)
  212.     //{{AFX_MSG_MAP(CRectThread)
  213.         // NOTE - the ClassWizard will add and remove mapping macros here.
  214.     //}}AFX_MSG_MAP
  215. END_MESSAGE_MAP()
  216.  
  217. CRectThread::CRectThread(CWnd* pWnd, HDC hDC, CPoint ptPos, CPoint ptVel, 
  218.     CSize Size, COLORREF color) : CGDIThread(pWnd, hDC)
  219. {
  220.     m_rectPosition.SetRect(ptPos.x ,ptPos.y, ptPos.x+Size.cx, ptPos.y+Size.cy);
  221.     m_ptVelocity = ptVel;
  222.  
  223.     CBrush brush(color);
  224.     m_hBrush = (HBRUSH)brush.Detach();
  225. }
  226.  
  227. BOOL CRectThread::InitInstance()
  228. {
  229.     m_brush.Attach(m_hBrush);
  230.  
  231.     return CGDIThread::InitInstance();
  232. }
  233.  
  234. void CRectThread::SingleStep()
  235. {
  236.     m_rectPosition.OffsetRect(m_ptVelocity);
  237.  
  238.     if (m_rectPosition.top<m_rectBorder.top) 
  239.         m_ptVelocity.y = (m_ptVelocity.y>0) ? m_ptVelocity.y : -m_ptVelocity.y;
  240.  
  241.     if (m_rectPosition.bottom>m_rectBorder.bottom) 
  242.         m_ptVelocity.y = (m_ptVelocity.y>0) ? -m_ptVelocity.y : m_ptVelocity.y;
  243.  
  244.     if (m_rectPosition.left<m_rectBorder.left) 
  245.         m_ptVelocity.x = (m_ptVelocity.x>0) ? m_ptVelocity.x : -m_ptVelocity.x;
  246.  
  247.     if (m_rectPosition.right>m_rectBorder.right) 
  248.         m_ptVelocity.x = (m_ptVelocity.x>0) ? -m_ptVelocity.x : m_ptVelocity.x;
  249.                      
  250.     // Since all threads share the same HDC it is necessary
  251.     // to block all other threads while we render in the HDC
  252.  
  253.     // NOTE: We don't have to call csl.Unlock() since the csl lock is
  254.     //       destroyed when leave this function.
  255.     CSingleLock csl( &CGDIThread::m_oCriticalSection );
  256.     if (csl.Lock())
  257.     {
  258.         CBrush* oldbrush;
  259.         
  260.         oldbrush = m_dc.SelectObject(&m_brush);
  261.         m_dc.Rectangle(m_rectPosition);
  262.         m_dc.SelectObject(oldbrush);
  263.     }
  264.     csl.Unlock();
  265. }
  266.  
  267. /////////////////////////////////////////////////////////////////////////////
  268. // CLineThread
  269.  
  270. IMPLEMENT_DYNAMIC(CLineThread, CGDIThread)
  271.  
  272. BEGIN_MESSAGE_MAP(CLineThread, CCmdTarget)
  273.     //{{AFX_MSG_MAP(CLineThread)
  274.         // NOTE - the ClassWizard will add and remove mapping macros here.
  275.     //}}AFX_MSG_MAP
  276. END_MESSAGE_MAP()
  277.  
  278. CLineThread::CLineThread(CWnd* pWnd, HDC hDC, CPoint ptPos1, CPoint ptVel1, 
  279.     CPoint ptVel2, CSize Size, COLORREF color) : CGDIThread(pWnd, hDC)
  280. {
  281.     m_ptPosition1 = ptPos1;
  282.     m_ptPosition2 = ptPos1 + Size;
  283.     m_ptVelocity1 = ptVel1;
  284.     m_ptVelocity2 = ptVel2;
  285.  
  286.     CPen pen(PS_SOLID, 1, color);
  287.     m_hPen = (HPEN)pen.Detach();
  288. }
  289.  
  290. BOOL CLineThread::InitInstance()
  291. {
  292.     m_pen.Attach(m_hPen);
  293.  
  294.     return CGDIThread::InitInstance();
  295. }
  296.  
  297. void CLineThread::SingleStep()
  298. {
  299.     m_ptPosition1.Offset(m_ptVelocity1);
  300.     m_ptPosition2.Offset(m_ptVelocity2);
  301.  
  302.     if (m_ptPosition1.y<m_rectBorder.top) 
  303.         m_ptVelocity1.y = (m_ptVelocity1.y>0) ? m_ptVelocity1.y : -m_ptVelocity1.y;
  304.     else if (m_ptPosition1.y>m_rectBorder.bottom)                                    
  305.         m_ptVelocity1.y = (m_ptVelocity1.y>0) ? -m_ptVelocity1.y : m_ptVelocity1.y;
  306.  
  307.     if (m_ptPosition2.y<m_rectBorder.top) 
  308.         m_ptVelocity2.y = (m_ptVelocity2.y>0) ? m_ptVelocity2.y : -m_ptVelocity2.y;
  309.     else if (m_ptPosition2.y>m_rectBorder.bottom)                                    
  310.         m_ptVelocity2.y = (m_ptVelocity2.y>0) ? -m_ptVelocity2.y : m_ptVelocity2.y;
  311.  
  312.     if (m_ptPosition1.x<m_rectBorder.left) 
  313.         m_ptVelocity1.x = (m_ptVelocity1.x>0) ? m_ptVelocity1.x : -m_ptVelocity1.x;
  314.     else if (m_ptPosition1.x>m_rectBorder.right)                                    
  315.         m_ptVelocity1.x = (m_ptVelocity1.x>0) ? -m_ptVelocity1.x : m_ptVelocity1.x;
  316.  
  317.     if (m_ptPosition2.x<m_rectBorder.left) 
  318.         m_ptVelocity2.x = (m_ptVelocity2.x>0) ? m_ptVelocity2.x : -m_ptVelocity2.x;
  319.     else if (m_ptPosition2.x>m_rectBorder.right)                                    
  320.         m_ptVelocity2.x = (m_ptVelocity2.x>0) ? -m_ptVelocity2.x : m_ptVelocity2.x;
  321.  
  322.     // Since all threads share the same HDC it is necessary
  323.     // to block all other threads while we render in the HDC
  324.  
  325.     // NOTE: We don't have to call csl.Unlock() since the csl lock is
  326.     //       destroyed when leave this function.
  327.     CSingleLock csl( &CGDIThread::m_oCriticalSection );
  328.     if (csl.Lock())
  329.     {
  330.         CPen* oldpen;
  331.  
  332.         oldpen = m_dc.SelectObject(&m_pen);
  333.         m_dc.MoveTo(m_ptPosition1);
  334.         m_dc.LineTo(m_ptPosition2);
  335.         m_dc.SelectObject(oldpen);
  336.     }
  337.     csl.Unlock();
  338. }
  339.